/**
 * DSM - Distributed Search Manager
 * Developed by Milspec Research International Pty Ltd
 * $Author: vhobbs $
 * $Revision: 1.7 $
 * $Date: 2006/09/13 00:14:36 $
 * (c)Copyright 2004
 * education.au limited 
 * DEST
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this 
 * list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution.
 * Neither the names education.au limited, DEST nor the names of its 
 * contributors may be used to endorse or promote products derived from this 
 * software without specific prior written permission.
 * To the extent permitted by law, the copyright owners of this software and 
 * its contributors:
 * (i) exclude all warranties in relation to the software; and
 * (ii) exclude liability for all losses, costs, expenses and damages arising 
 * in any way from the use of the software whether arising from or in 
 * relation to breach of contract, negligence or any other tort, in equity
 * or otherwise. If the software is in breach of a warranty which is 
 * implied by law, the copyright owners and contributors liability is
 * limited to the replacement of the software.
 * 
 * @author	gsingh
 */

package au.edu.educationau.opensource.dsm.util;

import java.util.StringTokenizer;

/**
 * String Manipulation Utilities - many of which are available within the JDK.
 */

public class StringUtils {
	private static final String NUMERIC_ENTITY_EXPRESSION = "&#[0-9]+;";
	private static final String CONTAINS_NUMERIC_ENTITY_EXPRESSION = "&#[0-9]+;";
	private static final String NAMED_ENTITY_EXPRESSION = "&[a-zA-Z]+;";
	private static final String CONTAINS_NAMED_ENTITY_EXPRESSION = ".*&[a-zA-Z]+;.*";

	/**
	 * replaceAll could be replaced with JDK 1.4.x String.replaceAll
	 * 
	 * @param original
	 * @param find
	 * @param replacement
	 */
	public static String replaceAll(String original, String find, String replacement) {
		StringBuffer buffer = new StringBuffer(original);

		int idx = original.length();
		int offset = find.length();

		while ((idx = original.lastIndexOf(find, idx - 1)) > -1) {
			buffer.replace(idx, idx + offset, replacement);
		}

		return buffer.toString();
	}

	/**
	 * replaceAll could be replaced with JDK 1.4.x String.replaceAll
	 * 
	 * @param buffer
	 * @param find
	 * @param replacement
	 */
	public static StringBuffer replaceAll(StringBuffer buffer, String find, String replacement) {

		int bufidx = buffer.length() - 1;
		int offset = find.length();
		while (bufidx > -1) {
			int findidx = offset - 1;
			while (findidx > -1) {
				if (bufidx == -1) {
					// Done
					return buffer;
				}
				if (buffer.charAt(bufidx) == find.charAt(findidx)) {
					findidx--; // Look for next char
					bufidx--;
				} else {
					findidx = offset - 1; // Start looking again
					bufidx--;
					if (bufidx == -1) {
						// Done
						return buffer;
					}
					continue;
				}
			}
			buffer.replace(bufidx + 1, bufidx + 1 + offset, replacement);
			// start looking again
		}
		// No more matches
		return buffer;

	}

	/**
	 * Takes an array of tokens and converts into separator-separated string.
	 * 
	 * @param array
	 *            ?String?[] The array of strings input.
	 * @param separators
	 *            ?String? The string separator.
	 * @return String A string containing tokens separated by seperator.
	 */
	public static final String arrayToString(String[] array, String separators) {
		StringBuffer sb = new StringBuffer("");
		String empty = "";

		if (array == null)
			return empty;

		if (separators == null)
			separators = ",";

		for (int ix = 0; ix < array.length; ix++) {
			if (array[ix] != null && !array[ix].equals("")) {
				sb.append(array[ix] + separators);
			}
		}
		String str = sb.toString();
		if (!str.equals("")) {
			str = str.substring(0, (str.length() - separators.length()));
		}
		return str;
	}

	/**
	 * Converts a delimited string into an array of string tokens.
	 * 
	 * @param str
	 *            ?String?[] The 'separator' separated string.
	 * @param separators
	 *            ?String? The string separator.
	 * @return String A string array of the original tokens.
	 */
	public static final String[] stringToArray(String str, String separators) {
		StringTokenizer tokenizer;
		String[] array = null;
		int count = 0;

		if (str == null)
			return array;

		if (separators == null)
			separators = ",";

		tokenizer = new StringTokenizer(str, separators);
		if ((count = tokenizer.countTokens()) <= 0) {
			return array;
		}

		array = new String[count];

		int ix = 0;
		while (tokenizer.hasMoreTokens()) {
			array[ix] = tokenizer.nextToken();
			ix++;
		}

		return array;
	}

	/**
	 * Remove a given set of characters from a String.
	 * 
	 * @param data
	 *            ?String? The input string to be cleansed of 'removeChars'.
	 * @param removeChars
	 *            ?String? The characters to be removed.
	 * @return String The new string cleansed of 'removeChars'.
	 */
	public static String removeChars(String data, String removeChars) {
		String temp = null;
		StringBuffer out = new StringBuffer();
		temp = data;

		StringTokenizer st = new StringTokenizer(temp, removeChars);
		while (st.hasMoreTokens()) {
			String element = (String) st.nextElement();
			out.append(element);
		}
		return out.toString();
	}

	/**
	 * Check if the string is not null and is not empty after a trim
	 * 
	 * @param checkStr
	 *            ?checkstr?
	 * @return check
	 */
	public static boolean isEmpty(String checkStr) {
		return (null == checkStr);
	} // isEmpty

	/**
	 * checkString checks to see if the String is null and if it is, then
	 * returns the default.
	 * 
	 * @param inputString
	 * @param defaultString
	 * @return a properly formatted String object
	 */
	public static String checkString(String inputString, String defaultString) {
		if (!isEmpty(inputString)) {
			return inputString.trim();
		} // if
		else {
			return defaultString;
		} // else
	} // checkString

	/**
	 * String choice with bias toward newValue
	 * 
	 * @param newValue
	 * @param oldValue
	 * @param defaultValue
	 * @return a properly formatted String object
	 */
	public static String choiceString(String newValue, String oldValue, String defaultValue) {
		return checkString(newValue, checkString(oldValue, defaultValue));
	} // useLatestString

	/**
	 * Same as choice String except its dealing with String Arrays, useful for
	 * parameter values array you get back from the request object
	 * 
	 * @param newArray
	 * @param oldArray
	 * @param defaultArray
	 * @return a String array of values
	 */
	public static String[] choiceStringArray(String[] newArray, String[] oldArray, String[] defaultArray) {
		if (null != newArray && newArray.length > 0) {
			return newArray;
		} else if (null != oldArray && oldArray.length > 0) {
			return oldArray;
		} else {
			return defaultArray;
		}
	} // choiceStringArray

	/**
	 * @param str
	 */
	public static String nullifyOnEmpty(String str) {
		return (null == str || str.trim().length() <= 0) ? null : str.trim();
	}

	/**
	 * @param str
	 */
	public static String nnString(String str) {
		return (null == str || str.trim().length() <= 0) ? "" : str;
	}

	/**
	 * Removes accents and diacritics from a String returning a String with
	 * basic ASCII chars
	 * 
	 * @param s
	 *            String to be converted to ASCII form
	 * @return the original String in ASCII form
	 */
	public static String toASCII(String s) {
		// Remove HTML entity characters
		// and perform the conversion from unicode
		byte[] bytes = s.replaceAll(NUMERIC_ENTITY_EXPRESSION, "").replaceAll(NAMED_ENTITY_EXPRESSION, "").getBytes();
		StringBuffer buffer = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			if ((int) bytes[i] > 0)
				buffer.append((char) bytes[i]);
		}
		return buffer.toString();
	} // toASCII

	/**
	 * @param s
	 *            the String to be converted
	 * @return a String with all entities converted to corresponding unicode
	 *         chars
	 */
	public static String entityToUnicode(String s) {
		StringBuffer buffer = new StringBuffer();
		if (s.matches(CONTAINS_NUMERIC_ENTITY_EXPRESSION) || s.matches(CONTAINS_NAMED_ENTITY_EXPRESSION)) {
			// find first entity
			int startpos = s.indexOf("&#");
			int endpos = s.indexOf(";", startpos);
			buffer.append(s.substring(0, startpos));
			buffer.append(entityCharToUnicode(s.substring(startpos, endpos + 1)));
			buffer.append(entityToUnicode(s.substring(endpos + 1)));
		} else {
			// no entites in string, we are done
			return s;
		}
		return buffer.toString();
	}

	/**
	 * Transform a numeric HTML entity into the corresponding Unicode
	 * 
	 * @param s
	 *            the entity
	 * @return the unicode representation (as a String with one character)
	 */
	public static String entityCharToUnicode(String s) {
		try {
			int unicode = Integer.parseInt(s.substring(2, s.length() - 1));
			return new String(new char[] { (char) unicode });
		} catch (NumberFormatException nfe) {
			// TODO: handle named entitites here, if required
			return s;
		}
	}

}
